home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / LibraryOfCongress / LibraryOfCongress.app / Storm.m < prev    next >
Encoding:
Text File  |  1992-08-07  |  15.7 KB  |  707 lines

  1. /*
  2.  * Interface for network Library of Congress search service.
  3.  *
  4.  * Michael Hawley
  5.  * MIT Media Laboratory
  6.  * 20 Ames Street
  7.  * Cambridge, MA 02139
  8.  * mike@media-lab.mit.edu
  9.  * Copyright (c) 1991 MIT Media Laboratory
  10.  * Burn before reading!  This means you!!
  11.  *
  12.  * Please forward any comments/revisions.
  13.  */
  14.  
  15. #import "Storm.h"
  16. #import "Process.h"
  17. #import <appkit/Form.h>
  18. #import <appkit/Font.h>
  19. #import <appkit/Text.h>
  20. #import <appkit/TextField.h>
  21. #import <appkit/Button.h>
  22. #import <appkit/PopUpList.h>
  23. #import <appkit/ScrollView.h>
  24. #import <appkit/Matrix.h>
  25. #import <appkit/NXBrowser.h>
  26. #import "MyMenuCell.h"
  27. #import "Defaults.h"
  28. #import "util.h"
  29.  
  30. @implementation Storm
  31.  
  32. int StormDebug = 1;
  33. id _status;
  34. extern setState(), ReadState(), runState(), access(), 
  35.        getReport(), sleep(), execState();
  36.  
  37. int confirm(a,b,c,d) char *a,*b,*c,*d; {
  38.     char t[1024];
  39.     extern int NXApp;
  40.     sprintf(t,a,b,c,d);
  41.     return NXRunAlertPanel([NXApp appName],t,"Yes","No",NULL)==1;
  42. }
  43.  
  44. char *
  45. path(char *s)
  46. /*
  47.  * if 's' is in [NXArgv[0]], return [NXArgv[0]]/s.
  48.  * (for looking up internal commands and files in .../Opener.app/...).
  49.  */
  50. {
  51.     char t[1024], *q, *r;
  52.     static char p[1024];
  53.     extern char **NXArgv;
  54.     *t = '\0';
  55.     sscanf(s,"%s",t);
  56.     if (!*t || *t=='(') return s;
  57.     r = s + strlen(t);
  58.     strcpy(p,*NXArgv);
  59.     if (q=rindex(p,'/'))
  60.         strcpy(q+1,t);
  61.     else
  62.         strcpy(p,t);
  63.     if (access(p,0)==0){
  64.         strcpy(p+strlen(p),r);
  65.         return p;
  66.     }
  67.     return s;
  68. }
  69.  
  70. static void say(s, a,b,c,d) id s; char *a,*b,*c,*d; {
  71.     char p[1024];
  72.     sprintf(p,a,b,c,d);
  73.     [s setStringValue:p];
  74.     [s display];
  75.     NXPing();
  76. }
  77.  
  78. void message(a,b,c,d) char *a,*b,*c,*d; {
  79.     say(_status,a,b,c,d);
  80. }
  81.  
  82. /*
  83.  * These two routines are for tracking net activity.
  84.  */
  85. static void
  86. monitorMail(subj,body,dest) char *subj, *body, *dest; {
  87.     char s[1024];
  88.     if (!dest || !*dest) dest = "monitor@tome.media.mit.edu";
  89.     if (body && *body) sprintf(s,"echo %s",body);
  90.     else strcpy(s,"(whoami ; hostname)");
  91.     sprintf(s+strlen(s),"| /usr/ucb/Mail -s \"%s\" %s &",
  92.     subj && *subj? subj : [NXApp appName], dest);
  93.     system(s);
  94. }
  95.  
  96. static void
  97. monitor(subj) char *subj; { // send a note at first use.  to track net.
  98.     char s[1024], *suf = "loc";
  99.     sprintf(s,"%s/.NeXT/.%s",getenv("HOME"),suf);
  100.     if (access(s,0)){
  101.     FILE *f = fopen(s,"w");
  102.     if (f) fclose(f), monitorMail(subj,0,0);
  103.     }
  104. }
  105.  
  106. static int eq(char *a, char *b){ return strncmp(a,b,strlen(b))==0; }
  107.  
  108. id _P;
  109.  
  110. static void put(P, fmt, a, b, c, d) id P; char *fmt, *a, *b, *c, *d; {
  111.     char p[1024];
  112.     sprintf(p,fmt,a,b,c,d);
  113.     if (Verbose) printf("+ %s\n",p);
  114.     [P puts:p]; 
  115. }
  116.  
  117. void Put(fmt, a, b, c, d) char *fmt, *a, *b, *c, *d; {
  118.     put(_P,fmt,a,b,c,d);
  119. }
  120.  
  121.  
  122. static char *
  123. get(P, s, n) id P; char *s; int n; {
  124.     [P gets:s:n];
  125.     if (*s && Verbose) printf("> %s",s);
  126.     return *s? s : (char *)0; 
  127. }
  128.  
  129. char *
  130. pgets(s,n) char *s; int n; {
  131.     [_P gets:s:n];
  132.     cleanEsc(s);
  133.     return *s? s : (char *)0; 
  134. }
  135.  
  136. char *
  137. pgetsx(s,n) char *s; int n; {
  138.     [_P gets:s:n];
  139.     return *s? s : (char *)0; 
  140. }
  141.  
  142. char
  143. pgetc() {
  144.     char c = [_P getc];
  145.     if (c == 27 || c== '['){
  146.         while ((c = [_P getc]) != 'H' /* && c != 'm'*/ && c != '\n' && c != '\r') ;
  147.         if (c=='H' || c=='m') c = [_P getc];
  148.     }
  149.     return c;
  150. }
  151.  
  152. #ifdef 0
  153. static char *
  154. flush(P,s) id P; char *s; {
  155.     static char t[1024];
  156.     while (get(P,t,sizeof t))
  157.         if (strindex(t,s)) return t;
  158.     sleep(1);
  159.     while (get(P,t,sizeof t))
  160.         if (strindex(t,s)) return t;
  161.     return (char *)0;
  162. }
  163. #endif
  164.  
  165. char *
  166. Flush(s) char *s; {
  167.     static char t[1024];
  168.     if (_P) return (char *)0;
  169.     while (get(_P,t,sizeof t))
  170.         if (strindex(t,s)) return t;
  171.     sleep(1);
  172.     while (get(_P,t,sizeof t))
  173.         if (strindex(t,s)) return t;
  174.     return (char *)0;
  175. }
  176.  
  177. - enable:(BOOL)b {
  178.     [attachB setIcon:b? "plug" : "unplug"];
  179.     return self;
  180. }
  181.  
  182. static id _text, _scroll;
  183.  
  184. - initMatrix {
  185.     // from the nib file, we have the help text; keep a pointer to it.
  186.     _text = helpText = [scrollView docView];
  187.     [_text setDelegate:self];
  188.     [_text setMarginLeft:6.0 right:6.0 top:0.0 bottom:0.0];
  189.     [_text notifyAncestorWhenFrameChanged:YES];
  190.     return self;
  191. }
  192.  
  193. - setScrollView:anObject {
  194.     _scroll = scrollView = anObject;
  195.     [self initMatrix];
  196.     return self;
  197. }
  198.  
  199. extern char DefaultFont[];
  200. extern char DefaultFontSize[];
  201. static id fid = (id)0;
  202. static int canconvert = 0;
  203. double atof();
  204. char TextBuf[80000]="";
  205.  
  206. #import <appkit/FontManager.h>
  207.  
  208. prettyFormat(s) char *s; { // tweak fonts in a card catalog record
  209.     char *p = index(s,'\n')+1;
  210.     if (*s){ // italicize leading ...: fields
  211.       char *q = index(p,':');
  212.  
  213.       while (q && *q == ':'){
  214.           [_text setSel:p-s:q-s+1];
  215.           [_text setSelFontSize:[fid pointSize]*(12./14.)];
  216.           [_text setSelFontStyle:NX_ITALIC];
  217.           p = index(q,'\n'); if (p) p++;
  218.           if (p && *p) q = index(p,':');
  219.           else q = (char *)0;
  220.       }
  221.     }
  222. }
  223.  
  224. /*
  225.  * This is called as a TimedEntry as a kludge -- the effect we want
  226.  * is for the user to change the font in the text view, and then to
  227.  * apply the prettyFormat() to it.  The problem is that textWillConvert
  228.  * will be invoked for every font change and we want to do this
  229.  * after the smoke has cleared.
  230.  */
  231. hackToEnforceFonts(DPSTimedEntry n, double now, char *userData) {
  232.     if (canconvert && *TextBuf){ // reformat current entry
  233.     id w = [_scroll window];
  234.     char *s = TextBuf, *p = index(s,'\n')+1;
  235.     static NXPoint origin = {0.0,0.0};
  236.         DPSRemoveTimedEntry(n);
  237.     canconvert=0;
  238.     [w disableFlushWindow];
  239.     //[_text setText:s];
  240.     [_text setSel:p-s:strlen(s)];
  241.     [_text setSelGray:0.0];
  242.     [_text setSelFont:fid];
  243.  
  244.     prettyFormat(s);
  245.  
  246.     [_text selectNull];
  247.     [_text scrollPoint:&origin];
  248.     [_scroll display];
  249.     [[w reenableFlushWindow] flushWindow];
  250.     canconvert=1;
  251.         [_text setDelegate:userData];
  252.     }
  253. }
  254.  
  255. - textWillConvert:textObject fromFont:from toFont:to {
  256.     if (canconvert && (strcmp(DefaultFont,[from name])==0 ||
  257.     atof(DefaultFontSize) == [from pointSize])){
  258.     strcpy(DefaultFont,[to name]);
  259.     sprintf(DefaultFontSize,"%f",[to pointSize]);
  260.     fid = to;
  261.         writeDefaults();
  262.         [_text setDelegate:0];
  263.         DPSAddTimedEntry(0.,hackToEnforceFonts,self,100);
  264.     }
  265.     return to;
  266. }
  267.  
  268. void
  269. setText(s) char *s; {
  270.     static NXPoint origin = {0.0,0.0};
  271.     char *p = index(s,'\n')+1;  /* skip past first (blank) line */
  272.     id w = [_scroll window];
  273.  
  274.     if (!fid){
  275.         fid = [Font newFont:DefaultFont size:atof(DefaultFontSize)];
  276.     }
  277.     canconvert=0;
  278.     [w disableFlushWindow];
  279.     [_text setText:s];
  280.     [_text setSel:p-s:strlen(s)];
  281.     [_text setSelGray:0.0];
  282.     [_text setSelFont:fid];
  283.  
  284.     prettyFormat(s);
  285.  
  286.     [_text selectNull];
  287.     [_text scrollPoint:&origin];
  288.     [_scroll display];
  289.     [[w reenableFlushWindow] flushWindow];
  290.  
  291.     canconvert=1;
  292.     strcpy(TextBuf,s);
  293.  
  294.       if (TextBuf[0] && index(TextBuf,':')) [[_text delegate] enableOrder];
  295.       else [[_text delegate] disableOrder];
  296. }
  297.  
  298. void
  299. setFile(s) char *s; {
  300.     NXStream *f = NXMapFile(path(s),NX_READONLY);
  301.     static NXPoint origin = {0.0,0.0};
  302.     id w = [_scroll window];
  303.  
  304.     canconvert=0;
  305.     s = path(s);
  306.     if (!f) return ;
  307.     [w disableFlushWindow];
  308.     [_text setMonoFont:NO];
  309.     [_text readRichText:f];
  310.     [_text scrollPoint:&origin];
  311.     NXCloseMemory(f,NX_FREEBUFFER);
  312.     [_scroll display];
  313.     [[w reenableFlushWindow] flushWindow];
  314.     TextBuf[0] = '\0';
  315.     [[_text delegate] disableOrder];
  316. }
  317.  
  318. - showHelp:sender {
  319.     setFile("info");
  320.     return self;
  321. }
  322.  
  323. #define Case break; case
  324.  
  325. void
  326. squishRtn(char *s){
  327.     char *p = s;
  328.  
  329.     while (*p = *s++)
  330.         if (*p != '\r') ++p;
  331. }
  332.  
  333. static char *
  334. getLine(char *s, char *t){ /* read ...\n from s into t; return new s */
  335.     char *p = t;
  336.     *t = '\0';
  337.     squishRtn(s);
  338.     while (*s && *s != '\n') *p++ = *s++;
  339.     if (*s == '\n') *p++ = *s++;
  340.     *p++ = '\0';
  341.     if (*t == '\0') return (char *)0;
  342.     p = t;
  343.     return s;
  344. }
  345.  
  346. cleanEsc(s) char *s; {
  347.     if (*s == '[' || *s == 27){
  348.         char *p = s;
  349.         while (*p && *p != '\n' && *p != 'H') ++p;
  350.         if (*p == 'H') ++p;
  351.         strcpy(s,p);
  352.     }
  353.     return 1;
  354. }
  355.  
  356. - processOutput:(char *)s {
  357.     static char prev[8192]="";
  358.     char t[1024], *p=prev;
  359.     {
  360.         char *p = s;
  361.         while (*p){
  362.             if (*p == 27) *p = '\n';
  363.             p++;
  364.         }
  365.     }
  366.     strcat(prev,s); s = t;
  367.     while ((p=getLine(p,s)) && 
  368.            (index(s,'\n') && cleanEsc(s))){
  369.         if (Verbose) printf("- %s",s);
  370.         execState(0,s);
  371.     }
  372.     strcpy(prev,blank(s)?s:"");
  373.     return self;
  374. }
  375.  
  376. - hitFormat:sender {
  377.     extern setFormat();
  378.     extern char *cmdHelpText();
  379.     char *s = (char *)[[sender selectedCell] title];
  380.     setFormat(s);
  381.     [cmdHelp setStringValue:cmdHelpText()];
  382.     return self;
  383. }
  384.  
  385. id _browser;
  386.  
  387. - query:sender {
  388.     char buf[80000];
  389.     extern int LastItem;
  390.     char *fixQuery(), *s = fixQuery([form stringValueAt:0]);
  391.     if (!s || !*s){ // beep
  392.         return self;
  393.     }
  394.     _browser = browser;
  395.     enableMore(0);
  396.     resetItems(); [browser loadColumnZero];
  397.     Put("%s\r",s); pgets(buf,256);
  398.     getReport(buf,0);
  399.     [browser loadColumnZero];
  400.     [form selectTextAt:0];
  401.     if (LastItem == 3){
  402.         fixItem(buf);
  403.         setText(buf);
  404.     } else
  405.         setText("");
  406.     return self;
  407. }
  408.  
  409. static id me;
  410.  
  411. void
  412. Command(s) char *s; {
  413.     _P = [Process new:s delegate:me];
  414. }
  415.  
  416. - click:sender {
  417.     id c =  [[browser matrixInColumn:[browser lastColumn]] selectedCell];
  418.     if ([c isLeaf])
  419.         [c click:self];
  420.     return self;
  421. }
  422.  
  423. reload(DPSTimedEntry n, double now, char *userData) {
  424.     extern int MustReload;
  425.     DPSRemoveTimedEntry(n);
  426.     if (MustReload) [_browser loadColumnZero], MustReload = 0;
  427.     setText("");
  428. }
  429.  
  430. - (int)browser:sender fillMatrix:matrix inColumn:(int)column {
  431.     extern int NI;
  432.     return NI;
  433. }
  434.  
  435. - browser:sender loadCell:c atRow:(int)row inColumn:(int)column {
  436.     [c setContents:row];
  437.     return self;
  438. }
  439.  
  440. id _moreB;
  441.  
  442. - more:sender {
  443.     extern int LastItem;
  444.     char buf[80000];
  445.     Put("n\r"); pgets(buf,256);
  446.     getReport(buf,1);
  447.     [browser loadColumnZero];
  448.     [form selectTextAt:0];
  449.     if (LastItem == 3){
  450.         fixItem(buf);
  451.         setText(buf);
  452.     } else
  453.         setText("");
  454.     return self;
  455. }
  456.  
  457. enableMore(n){
  458.     return [_moreB setEnabled:n];
  459. }
  460.  
  461. - login:sender {
  462.     if (_P) [_P free]; P = _P = (id)0;
  463.     _status = status;
  464.     _moreB = moreB;
  465.     ReadState(path("menus"));
  466.     [browser setDelegate:self];
  467.     [browser setCellPrototype:[[MyMenuCell alloc] init]];
  468.     [browser setAction:@selector(click:)];
  469.     [browser setTarget:self];
  470.     [attachB setIcon:"plug"];
  471.     [form selectTextAt:0];
  472.     runState("");
  473.     return self;
  474. }
  475.  
  476. - ready:sender {
  477.     resetItems(); [browser loadColumnZero];
  478.     [searchB setEnabled:1];
  479.     return self;
  480. }
  481.  
  482. - logout:sender {
  483.     if (P && _P) setState("Detach"), runState("");
  484.     if (P) [P terminate:self];
  485.     _P = P = (id)0;
  486.     [self enable:NO];
  487.     [attachB setIcon:"unplug"];
  488.     [searchB setEnabled:0];
  489.     message("not connected.");
  490.     return self;
  491. }
  492.  
  493. void
  494. ready(){
  495.     [me ready:me];
  496. }
  497.  
  498. void
  499. logout(){
  500.     [me logout:me];
  501. }
  502.  
  503. - ensurelogin {
  504.     //if (!_P) [self login:self];
  505.     return self;
  506. }
  507.  
  508. int
  509. ensurelogin(){
  510.     [me ensurelogin];
  511.     return _P? 1 : 0;
  512. }
  513.  
  514. - attach:sender {
  515.     if (eq((char *)[sender icon],"unplug")){
  516.         [self login:sender];
  517.     } else {
  518.         [self logout:sender];
  519.     }
  520.     return self;
  521. }
  522.  
  523. /*
  524.  * telnet:
  525.  */
  526. #import <appkit/Pasteboard.h>
  527. #import <appkit/Speaker.h>
  528. #import <appkit/Listener.h>
  529. - copyString:(char *)s {
  530.   id p = [Pasteboard new];
  531.   [p declareTypes:&NXAsciiPboard num:1 owner:self];
  532.   [p writeType:NXAsciiPboard data:s length:strlen(s)];
  533.   return self;
  534. }
  535.  
  536. - launchTerminal:(char *)program {
  537.   id p = [NXApp appSpeaker];
  538.   port_t t = NXPortFromName("Terminal",NULL);
  539.   int ok;
  540.   if (t==PORT_NULL) return self;
  541.   [p setSendPort:t];
  542.   [self copyString:program];
  543.   (void)[p msgPaste:&ok];
  544.   return self;
  545. }
  546.  
  547. - (char *)service {
  548.     char *s = "dra.com"; // (char *)[[format selectedCell] title];
  549.     return s && *s? s : "192.65.218.43";
  550. }
  551.  
  552. - telnet:sender {
  553.     char s[1024];
  554.     sprintf(s,"telnet %s\n", [self service]);
  555.     [self launchTerminal:s];
  556.     return self;
  557. }
  558.  
  559. - sendComments:sender {
  560.     return self;
  561. }
  562.  
  563. char *
  564. orderForm(){
  565.     static char s[1024]="";
  566.     char *h;
  567.     if (*s) return s;
  568.     h = getenv("HOME");
  569.     if (!h || !*h) sprintf(s,"/tmp");
  570.     else sprintf(s,"%s/.NeXT",h);
  571.     strcat(s,"/BookOrderForm");
  572. }
  573.  
  574. - editOrder:sender {
  575.     if (access(orderForm(),0)){
  576.         System("cp %s %s",path("BookOrderForm"),orderForm());
  577.     }
  578.     System("open %s",orderForm());
  579.     return self;
  580. }
  581.  
  582. - enableOrder {
  583.     [orderB setEnabled:YES];
  584.     [orderMenuB setEnabled:YES];
  585.     return self;
  586. }
  587.  
  588. - disableOrder {
  589.     [orderB setEnabled:NO];
  590.     [orderMenuB setEnabled:NO];
  591.     return self;
  592. }
  593.  
  594. - sendOrder:sender {
  595.     char t[1024],t2[1024],body[80000], *Body = body;
  596.     char to[1024] = "", cc[1024]="", subj[1024]="";
  597.     FILE *f;
  598. #define fcall(a)  [s performRemoteMethod:a]
  599. #define call(a,b) [s performRemoteMethod:a with:b length:strlen(b)+1]
  600.     id s = [NXApp appSpeaker];
  601.  
  602.     if (access(orderForm(),0)){
  603.         if (confirm("You need to edit the order form...")){
  604.             [self editOrder:self];
  605.             //monitorMail("LibraryOfCongress-1.0-order",0,0);
  606.         }
  607.         return self;
  608.     }
  609.  
  610.     strcpy(to,"quanbook@world.std.com");
  611.     strcpy(subj,"another e-mail book order");
  612.     strcpy(cc,"whoami"); execstr(cc); stripnl(cc);
  613.  
  614.     *body = '\0';
  615.     if (strindex(TextBuf,"Type of Material:")){
  616.         char *p, c[1024], t[80000];
  617.     sprintf(t, "/tmp/book-order%d",getpid());
  618.     sprintf(t2,"/tmp/book-info%d",getpid());
  619.     System("sed '/^#/d' %s > %s",orderForm(),t);
  620.     f = fopen(t2,"w");
  621.     if (!f){
  622.         confirm("Couldn't create scratch file (%s)",t2);
  623.     } else {
  624.         write(fileno(f),TextBuf,strlen(TextBuf));
  625.         write(fileno(f),"Body:\n",6);
  626.             //strcpy(t,TextBuf+1); sub(t,'\t',' ');
  627.         write(fileno(f),TextBuf+1,strlen(TextBuf+1));
  628.         write(fileno(f),"Body:\n",6);
  629.         fclose(f);
  630.     }
  631.         sprintf(c,"sed '/^[a-zA-Z]* [a-zA-Z ]*:/s/ /_/' %s > %sa",t2,t2);
  632.         system(c);
  633.         sprintf(c,"%s %s < %sa > %sa",path("rtfcast"),t,t2,t);
  634.         system(c);
  635.         unlink(t); unlink(t2); strcat(t,"a"); strcat(t2,"a");
  636.         f = fopen(t,"r");
  637.     if (!f){
  638.         confirm("Couldn't read scratch file (%s)",t);
  639.     } else {
  640.         int n = read(fileno(f),body,sizeof(body));
  641.         if (n > 0) body[n] = '\0';
  642.             fclose(f);
  643.     }
  644.         unlink(t); unlink(t2);
  645.         if (((p = strindex(Body,"To:")) ||
  646.              (p = strindex(Body,"to:"))) &&
  647.              (p == Body || p[-1] == '\n')){
  648.             sscanf(skipsp(index(p,':')+1),"%[^\n]",to);
  649.             if (p==Body) Body = index(p,'\n')+1;
  650.         }
  651.         if (((p = strindex(Body,"Subject:")) ||
  652.              (p = strindex(Body,"subject:"))) &&
  653.              (p == Body || p[-1] == '\n')){
  654.             sscanf(skipsp(index(p,':')+1),"%[^\n]",subj);
  655.             if (p==Body) Body = index(p,'\n')+1;
  656.         }
  657.         if (((p = strindex(Body,"Cc:")) ||
  658.              (p = strindex(Body,"cc:"))) &&
  659.              (p == Body || p[-1] == '\n')){
  660.             sscanf(skipsp(index(p,':')+1),"%[^\n]",cc);
  661.             if (p==Body) Body = index(p,'\n')+1;
  662.         }
  663.     }
  664.  
  665.     NXPortFromName("Mail", NULL); // make sure app is launched
  666.     [s setSendPort:NXPortFromName("MailSendDemo", NULL)];
  667.  
  668.     call("setTo:",to);
  669.     call("setSubject:",subj);
  670.     call("setCc:",cc);
  671.     call("setBody:",Body);
  672.     
  673.     return self;
  674. }
  675.  
  676. - print:sender {
  677.     [_text printPSCode:sender];
  678.     return self;
  679. }
  680.  
  681. + new {
  682.     me = self = [[Storm alloc] init];
  683.     return self;
  684. }
  685.  
  686. - free {
  687.     [self logout:self];
  688.     return [super free];
  689. }
  690.  
  691. - appDidInit:sender {
  692.     openDefaults();
  693.     if (FirstUse()) [license show:self],
  694.                     strcpy(DefaultFont,"Helvetica-Bold"),
  695.                     strcpy(DefaultFontSize,"18.0");
  696.     [attachB performClick:sender];
  697.     return self;
  698. }
  699.  
  700. - appWillTerminate:sender {
  701.     [self logout:self];
  702.     writeDefaults();
  703.     return self;
  704. }
  705.  
  706. @end
  707.